﻿package br.com.ir.tcc.geco.service;

import java.util.List;

import net.sourceforge.yamlbeans.YamlException;

import org.apache.commons.beanutils.BeanUtils;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import br.com.ir.tcc.geco.helper.PaginationHelper;
import br.com.ir.tcc.geco.modelo.Combinacao;
import br.com.ir.tcc.geco.modelo.CombinacaoTemplate;
import br.com.ir.tcc.geco.modelo.Modelo;
import br.com.ir.tcc.geco.web.Message;

@Component
@Scope(value = "prototype")
public class ModeloService extends GenericService {


	/*Remove o modelo indicado pelo parametro*/
	public Message removerModelo(Integer modeloId){
		
		Object identity = null;
		
		try {
			identity = HibernateSession.createSession();
			Session session = HibernateSession.getSession();
			Modelo modelo = (Modelo) session.get(Modelo.class, modeloId);
			session.delete("br.com.ir.tcc.geco.modelo.Modelo", modelo);
			session.flush();
		} catch (Exception e) {
			e.printStackTrace();
			return new Message("Ocorreu um erro ao tentar remover o modelo", Message.ERROR);
		}finally{
			closeSession(identity);
		}
		return new Message("O modelo foi removido com sucesso", Message.SUCCESS);
	}
	
	/*
	 * Verifica se existe combinação para o modelo indicado.
	 */
	public Message existeCombinacaoComModelo(Integer modelo_id) throws Exception{
		
		Object identity = null;
		
		try {
			identity = HibernateSession.createSession();
			Session session = HibernateSession.getSession();
			
			Query q = session.createQuery("from Combinacao c where 1=1 and c.modelo.id = :id");
			q.setParameter("id", modelo_id);
			int size = q.list().size();
			if(size > 0){
				return new Message("Este modelo já possui uma combinação salva, se prosseguir a combinação poderá ficar inválida.\nDeseja continuar?", Message.WARN);
			}
		} finally{
			closeSession(identity);
		}
		
		return null;
		
	}
	
	/*Carrega um modelo existente*/
	public Message loadModelo(Integer modeloId){
		Object identity = null;
		try {
			identity = HibernateSession.createSession();
			Session session = HibernateSession.getSession();
			Modelo modelo = (Modelo) session.get(Modelo.class, modeloId);
			return new Message("O modelo foi carregado", Message.SUCCESS, modelo);
		} catch (Exception e) {
			e.printStackTrace();
			return new Message(e.getMessage(), Message.ERROR);
		} finally{
			closeSession(identity);
		}
	}
	
	/*Remove as combinações existentes*/
	public void removerCombinacoes(Integer modeloId) {
		
		Object identity = null;
		
		try {
			identity = HibernateSession.createSession();
			Session session = HibernateSession.getSession();
			Query query = session.createQuery(
					"FROM Combinacao c WHERE c.modelo.id = :modeloId").setParameter(
					":modeloId", modeloId
			);

			List<Combinacao> combinacoes = query.list();
			for (Combinacao combinacao : combinacoes) {
				for (CombinacaoTemplate combinacaoTemplate : combinacao.getCombinacaoTemplates()) {
					session.delete(combinacaoTemplate);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeSession(identity);
		}
		
	}
	
	/*Salva o modelo indicado*/
	public Message salvarNovoModelo(Modelo modelo){
		Object identity = null;
		Transaction tx = null;
		
		try {
			identity = HibernateSession.createSession();
			Session session = HibernateSession.getSession();
			tx = session.getTransaction();
			tx.begin();
			session.save(modelo);
			session.flush();
			tx.commit();
			return new Message("O modelo foi salvo com sucesso", Message.SUCCESS);
		} catch (Exception e) {
			tx.rollback();
			e.printStackTrace();
			return new Message("Ocorreu um erro ao tentar salvar o modelo", Message.ERROR);
		}finally{
			closeSession(identity);
		}
	}
	
	/*Atualiza um modelo*/
	public Message atualizaModelo(Modelo modelo) {
		
		Object identity = null;
		Transaction tx = null;
		
		try {
			identity = HibernateSession.createSession();
			Session session = HibernateSession.getSession();
			tx = session.getTransaction();
			
			if(modelo.getId() == null) {
				throw new Exception("O modelo informado ainda não foi salvo");
			}
			tx.begin();
			session.merge(modelo);
			session.flush();
			tx.commit();
			
			return new Message("O modelo foi atualizado com sucesso", Message.SUCCESS);
		} catch (Exception e) {
			tx.rollback();
			e.printStackTrace();
			return new Message("Ocorreu um erro ao tentar atualizar o modelo", Message.ERROR);
		}finally{
			closeSession(identity);
		}
	}
	
	public String salvarModelo(Modelo modelo, boolean remocaoCombinacaoDireta) {

		Object identity = null;
		Transaction tx = null;

		try {

			identity = HibernateSession.createSession();
			Session session = HibernateSession.getSession();

			Object fonteModelo = modelo.getObjectModel();

			tx = session.getTransaction();
			tx.begin();

			// novo modelo
			if (modelo.getId() == null) {

				session.save(modelo);

			} else { // modelo existente

				Query query = session.createQuery(
						"FROM Combinacao c WHERE c.modelo = :modelo")
						.setParameter(":modelo", modelo);

				List<Combinacao> combinacoes = query.list();

				for (Combinacao combinacao : combinacoes) {

					for (CombinacaoTemplate combinacaoTemplate : combinacao
							.getCombinacaoTemplates()) {

						if (BeanUtils.getProperty(fonteModelo,
								combinacaoTemplate.getChaveObjetoModelo()) == null) {

							if (remocaoCombinacaoDireta) {
								session.delete(combinacaoTemplate);
							} else {
								throw new CombinacaoExistenteException(
										"Existem combina��es que precisam ser removidas.");
							}

						}

					}

				}

				session.save(modelo);

			}

			tx.commit();
			session.flush();
			
			return "O modelo foi salvo com sucesso";

		} catch (YamlException e) {
			throw new ServiceException("Erro ao converter o modelo");
		} catch (Exception e) {
			tx.rollback();
			throw new ServiceException(e);
		} finally {
			closeSession(identity);
		}
	}
	
	/* Busca todos os modelos cadastrados no sistema */
	@SuppressWarnings("unchecked")
	public List<Modelo> findAllModelos(){
		try {
			List<Modelo> modelos = null;
			modelos = (List<Modelo>) findAll("br.com.ir.tcc.geco.modelo.Modelo");
			return modelos;
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	
	/*Recupera uma página de resultados para Modelo*/
	public Message getPage(int page, int pageSize){
		try {
			List<Modelo> modelos = findAllModelos();
			PaginationHelper<Modelo> paginator = new PaginationHelper<Modelo>(modelos, pageSize);
			Message msg = new Message();
			msg.setContent(paginator.getPage(page));
			return msg;
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	public Integer[] getPageRange(Integer pageSize){
		PaginationHelper<Modelo> paginator = new PaginationHelper<Modelo>(findAllModelos(), pageSize);
		int total = paginator.getTotalPaginas();
		Integer[] range = new Integer[total];
		for(int i=0;i<total;i++){
			range[i] = i+1;
		}
		
		return range;
	}
	
	@SuppressWarnings("unchecked")
	public List<Modelo> searchModelos(String text){
		Object identity = null;
		
		try {
			identity = HibernateSession.createSession();
			Session session = HibernateSession.getSession();
			List<Modelo> modelos = null;
			Query q = session.createQuery("from Modelo modelo where 1=1 and lower(modelo.descricao) like lower(:text) or lower(modelo.yaml) like lower(:text) ");
			q.setString("text", '%' + text + '%');
			modelos = (List<Modelo>) q.list();
			return modelos;
		}
		catch ( Exception e) { 
			e.printStackTrace();
		} finally {
			closeSession(identity);
		}
		
		return null;
		
	}
}
